const {Surface, Vue} = window

Surface.component({
    name: 'curd',
    props: {
        components: {
            type: Array,
            default: () => []
        },
        componentMap: {
            type: Array,
            default: () => []
        },
        extComponent: { // 扩展组件
            type: Array,
            default: () => []
        },
        defaultForm: {
            type: Object,
            default:{
                options: {},
                columns: []
            }
        },
        defaultTable: {
            type: Object,
            default: {
                options: {},
                columns: []
            }
        },
    },
    setup(props) {
        const {onMounted, ref, nextTick} = Vue
        let jsonEditor = null
        onMounted(() => {
            jsonEditor = new window.JSONEditor(
                document.querySelector(".json-editor"),
                {
                    mode: 'code',
                    indentation: 4,
                    mainMenuBar: false,
                    onChange() {
                        curJSON.updating = true
                        jsonEditor.validate().then(err => {
                            if (err.length === 0) {
                                if (curJSON.onChange) {
                                    curJSON.onChange(jsonEditor.get())
                                }
                                curJSON.updating = false
                            }
                        })
                    }
                }
            );
        })
        const curJSON = {
            source: null,
            updating: false,
            onChange: null
        }

        /**
         * 设置JSON数据
         * @param source
         * @param onChange  监听修改事件
         * @param cover
         * @returns {Promise<boolean>}
         */
        const setJsonData = async function (source, onChange = null, cover = false) {
            const done = () => {
                curJSON.source = source
                curJSON.updating = false
                curJSON.onChange = onChange
                jsonEditor.set(source)
                return true
            }
            if (!cover && curJSON.updating) {
                await ElementPlus.ElMessageBox.confirm(
                    '当前内容正在更新中，是否覆盖?', '',
                    {confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning'}
                )
            }
            return done()
        }

        const formColumns = ref(props.defaultForm.columns || [])

        const formOptions = ref(Surface.merge({
            props: {
                inline: false,
                labelWidth: 100,
            }
        }, props.defaultForm.options))

        const tableColumns = ref(props.defaultTable.columns || [])

        const tableOptions = ref(Surface.merge({
            props: {
                data: [],
                border: false,
            },
            request: {
                url: ''
            },
            paginationProps: {}
        }, props.defaultTable.options))

        const curColumnIndex = ref(null)

        const curComponentTab = ref('component') // component || options

        const curFieldIndex = ref(null)

        const curPageTab = ref('table') // table || form

        const outputDialog = ref(false)

        const curOutputType = ref("curd") // table | form | curd
        const curOutputLang = ref("php") // php | vue1 | vue2

        /**
         *
         * @param jsonObj
         * @param depth number 初始缩进
         * @returns {string}
         */
        function json2PhpArr(jsonObj, depth = null) {
            let space = depth === null ? '' : '   '.repeat(depth)
            let wrap = depth === null ? '' : "\n"
            let phpArr = `[`;
            (function _handle(obj, depth = 1) {
                let space = depth === null ? '' : '   '.repeat(depth)
                const isArr = Array.isArray(obj)
                for (const key in obj) {
                    let val = obj[key]
                    // 数组不需要前缀
                    let keyPref = isArr ? "" : `"${key}" => `
                    if (typeof val === 'object') {
                        phpArr += `${wrap}${space}${keyPref}[`;
                        _handle(val, depth === null ? depth : depth + 1);
                        phpArr = phpArr.replace(/,+$/g, '')
                        phpArr += `${wrap}${space}],`;
                    } else {
                        phpArr += `${wrap}${space}${keyPref}${JSON.stringify(val)},`;
                    }
                }
            })(jsonObj, depth === null ? depth : depth + 1)
            phpArr = phpArr.replace(/,+$/g, '')
            phpArr += `${wrap}${space}]`;
            return phpArr;
        }

        /**
         *
         * @param json
         * @param pad 默认缩进
         * @param trim 移除前后换行符
         * @returns {string}
         */
        function formatJson(json, pad = 0, trim = true) {
            let reg = null,
                formatted = '',
                PADDING = '    '; // （缩进）可以使用'\t'或不同数量的空格
            let options = {
                newlineAfterColonIfBeforeBraceOrBracket: false, // 在 '{' or '[' follows ':'位置移除新行
                spaceAfterColon: true, // 在冒号后面加空格
            }
            // 开始格式化...
            if (typeof json !== 'string') {
                // 确保为JSON字符串
                json = JSON.stringify(json);
            } else {
                //已经是一个字符串，所以解析和重新字符串化以删除额外的空白
                json = JSON.parse(json);
                json = JSON.stringify(json);
            }
            // 在花括号前后添加换行
            reg = /([\{\}])/g;
            json = json.replace(reg, '\r\n$1\r\n');
            // 在方括号前后添加新行
            reg = /([\[\]])/g;
            json = json.replace(reg, '\r\n$1\r\n');
            // 在逗号后添加新行
            reg = /(\,)/g;
            json = json.replace(reg, '$1\r\n');
            // 删除多个换行
            reg = /(\r\n\r\n)/g;
            json = json.replace(reg, '\r\n');
            // 删除逗号前的换行
            reg = /\r\n\,/g;
            json = json.replace(reg, ',');
            // 可选格式...
            if (!options.newlineAfterColonIfBeforeBraceOrBracket) {
                reg = /\:\r\n\{/g;
                json = json.replace(reg, ':{');
                reg = /\:\r\n\[/g;
                json = json.replace(reg, ':[');
            }
            if (options.spaceAfterColon) {
                reg = /\:/g;
                json = json.replace(reg, ': ');
            }
            json.split('\r\n').forEach(function(node, index) {
                let i = 0,
                    indent = 0,
                    padding = '';
                if (node.match(/\{$/) || node.match(/\[$/)) {
                    indent = 1;
                } else if (node.match(/\}/) || node.match(/\]/)) {
                    if (pad !== 0) {
                        pad -= 1;
                    }
                } else {
                    indent = 0;
                }
                for (i = 0; i < pad; i++) {
                    padding += PADDING;
                }
                formatted += padding + node + '\r\n';
                pad += indent;
            });
            return trim ? formatted.replace(/^\s+|\s+$/g,'') : formatted;
        }

        function getRandomChar(len = 6) {
            const chars = 'abcdefghijklmnopqrstuvwxyz';
            return [...Array(len)].map(i => chars.charAt(Math.floor(Math.random() * chars.length))).join('');
        }

        const componentChildren = []
        const componentList = [
            {
                label: "常用组件",
                components: props.components
            }
            , ...props.extComponent
        ];
        if (componentList.length > 0) {
            componentList.forEach(ext => {
                componentChildren.push({el: "div", props: {class: "s-title"}, children: ext.label})

                componentChildren.push({
                    el: "draggable",
                    props: {
                        sort: false,
                        chosenClass: "s-chosen",
                        animation: 100,
                        group: {name: "curd", pull: "clone", put: false},
                        list: ext.components
                    },
                    children: {
                        __invoke: ({element}) => {
                            return {
                                el: 'div',
                                props: {
                                    class: 'item component ' + (formOptions.value.props.inline ? 'inline' : '')
                                },
                                children: [
                                    typeof element.icon === 'string' ? {
                                        el: 'div',
                                        props: {class: 'icon'},
                                        children: element.icon
                                    } : element.icon,
                                    {el: 'div', props: {class: 'label'}, children: element.label || ''}
                                ]
                            }
                        },
                        el: "component",
                        slot: "item"
                    }
                })
            })
        }

        function copyText(text) {
            let cInput = document.createElement("textarea")
            cInput.value = text
            document.body.appendChild(cInput)
            cInput.select()
            document.execCommand("copy")
            document.body.removeChild(cInput)
            ElementPlus.ElMessage({
                message: "复制成功",
                type: 'success',
            })
        }
        
        // 全局唯一key 用于组件刷新
        const uniqueKeyMap = {
            refresh(key){
                uniqueKeyMap[key] = getRandomChar(6)
            }
        }

        const reloadTableData = () => {
            if (!tableOptions.value.props.hasOwnProperty('data')) tableOptions.value.props.data = []
            const data = tableOptions.value.props.data.length > 0 ? tableOptions.value.props.data : Array(5).fill({})
            for (let i in data) {
                const item = {}
                tableColumns.value.forEach(col => {
                    item[col.props.prop] = data[i][col.props.prop] || ("内容：" + getRandomChar(3))
                })
                data[i] = item
            }
            tableOptions.value.props.data.splice(0, 5, ...data)
        }

        const reloadJsonEditor = async () => {
            let timer = null
            const timerHandler = func => {
                if (timer) clearTimeout(timer)
                timer = setTimeout(() => {
                    func()
                    clearTimeout(timer)
                    timer = null
                }, 300)
            }

            let setJsonPromise = null
            if (curComponentTab.value === 'component') {
                if (curPageTab.value === 'form') {
                    setJsonPromise = await setJsonData(formColumns.value[curFieldIndex.value], code => {
                        timerHandler(() => {
                            formColumns.value[curFieldIndex.value] = code
                        })
                    })
                } else {
                    setJsonPromise = await setJsonData(tableColumns.value[curColumnIndex.value], code => {
                        timerHandler(() => {
                            tableColumns.value[curColumnIndex.value] = code
                        })
                    })
                }
            } else if (curComponentTab.value === 'options') {
                if (curPageTab.value === 'form') {
                    setJsonPromise = await setJsonData(formOptions.value, code => {
                        timerHandler(() => {
                            formOptions.value = code
                        })
                    })
                } else {
                    setJsonPromise = await setJsonData(tableOptions.value, async code => {
                        if (!Surface.isEqual(code.request, tableOptions.value.request)) {
                            // 修改request才重新加载table
                            uniqueKeyMap.refresh("table")
                        }
                        tableOptions.value = code
                        // data数据设置为url请求时
                        try {
                            if (tableOptions.value.request.url && tableOptions.value.props.hasOwnProperty('data')) {
                                delete tableOptions.value.props['data']
                                curJSON.updating = false
                                await reloadJsonEditor()
                            } else if (!tableOptions.value.request.url && !tableOptions.value.props.hasOwnProperty('data')) {
                                reloadTableData()
                                curJSON.updating = false
                                await reloadJsonEditor()
                            }
                        } catch (e) {
                        }
                    })
                }
            }
            return setJsonPromise
        }

        let outputData = ""

        return () => new Surface.Render(
            {
                el: "div",
                props: {class: "s-curd-container"},
                children: [
                    curPageTab.value === 'form' ? {
                        el: "div",
                        props: {class: "left"},
                        children: componentChildren
                    } : '',
                    {
                        el: "div",
                        props: {class: "center"},
                        children: [
                            {
                                el: "el-row",
                                props: {class: "tools", justify: "end", align: 'middle'},
                                children: [
                                    {
                                        el: 'el-col',
                                        props: {span: 8},
                                        children: {el: 'a', props: {class: 's-title', href: "https://zsw.ink/"}, children: "Surface-CURD"}
                                    },
                                    {
                                        el: 'el-col',
                                        props: {span: 8},
                                        children: {
                                            el: 'el-row',
                                            props: {justify: "center"},
                                            children: {
                                                el: "radio",
                                                props: {
                                                    modelValue: curPageTab.value,
                                                    'onUpdate:modelValue':async val => {
                                                        let oldVal = curPageTab.value
                                                        curPageTab.value = val
                                                        try{
                                                            await reloadJsonEditor()
                                                        }catch (e){
                                                            curPageTab.value = oldVal
                                                        }
                                                    },
                                                    options: [
                                                        {"label": "表格", "value": 'table'},
                                                        {"label": "表单", "value": 'form'},
                                                    ]
                                                }
                                            }
                                        }
                                    },
                                    {
                                        el: 'el-col',
                                        props: {span: 8},
                                        children: {
                                            el: "el-row",
                                            props: {justify: "end"},
                                            children: {
                                                el: "el-button",
                                                props: {
                                                    onClick() {
                                                        outputDialog.value = true
                                                    }
                                                },
                                                children: "导出"
                                            }
                                        },
                                    }
                                ]
                            },
                            {
                                el: 'el-dialog',
                                props: {
                                    title: "导出",
                                    width: 800,
                                    appendToBody: true,
                                    destroyOnClose: true,
                                    modelValue: outputDialog.value,
                                    'onUpdate:modelValue': (val) => {
                                        outputDialog.value = val
                                    }
                                },
                                children: [
                                    {
                                        el: 'div',
                                        __invoke() {
                                            return {
                                                el: 'div',
                                                props: {
                                                    class: "s-output"
                                                },
                                                children: [
                                                    {
                                                        el: "el-tabs",
                                                        props: {
                                                            modelValue: curOutputType.value,
                                                            'onUpdate:modelValue': val => {
                                                                curOutputType.value = val
                                                            }
                                                        },
                                                        children: [
                                                            {
                                                                el: "el-tab-pane",
                                                                props: {label: "导出表格", name: 'table'}
                                                            },
                                                            {
                                                                el: "el-tab-pane",
                                                                props: {label: "导出表单", name: 'form'}
                                                            },
                                                            {
                                                                el: "el-tab-pane",
                                                                props: {label: "导出CURD", name: 'curd'}
                                                            }
                                                        ]
                                                    },
                                                    {
                                                        el: 'div',
                                                        props: {
                                                            class: "tab-2"
                                                        },
                                                        children: [
                                                            {
                                                                el: "el-tabs",
                                                                props: {
                                                                    tabPosition: "left", class: "lang",
                                                                    modelValue: curOutputLang.value,
                                                                    'onUpdate:modelValue': val => {
                                                                        curOutputLang.value = val
                                                                    }
                                                                },
                                                                children: [
                                                                    {
                                                                        el: "el-tab-pane",
                                                                        props: {label: "PHP源码", name: 'php'}
                                                                    },
                                                                    {
                                                                        el: "el-tab-pane",
                                                                        props: {label: "Vue风格一", name: 'vue1'}
                                                                    },
                                                                    {
                                                                        el: "el-tab-pane",
                                                                        props: {label: "Vue风格二", name: 'vue2'}
                                                                    }
                                                                ]
                                                            },
                                                            {
                                                                el: 'pre',
                                                                props: {
                                                                    class: "content"
                                                                },
                                                                children: function (){

                                                                    const outputHandler = {
                                                                        getTableOptions(){
                                                                            let options = Surface.cloneDeep(tableOptions.value)
                                                                            // 删除空数据
                                                                            if (options.props.hasOwnProperty('data') && Surface.isEmpty(options.props.data)) {
                                                                                delete options.props.data
                                                                            }
                                                                            if (options.hasOwnProperty('paginationProps') && Surface.isEmpty(options.paginationProps)) {
                                                                                delete options.paginationProps
                                                                            }

                                                                            return options
                                                                        },
                                                                        getTableColumn(){
                                                                            let classStr = []
                                                                            tableColumns.value.forEach(table => {
                                                                                let component = Surface.cloneDeep(table)
                                                                                delete component.el
                                                                                classStr.push(`(new TableColumn(${json2PhpArr(component, null)}))`)
                                                                            })
                                                                            return classStr
                                                                        },
                                                                        getPhpFormColumns(){
                                                                            let formNamespaceStr = {}
                                                                            let formColumnsStr = []

                                                                            const componentMap = props.componentMap

                                                                            formColumns.value.forEach(field => {
                                                                                let component = Surface.cloneDeep(field)
                                                                                let el = component.el.toLowerCase()
                                                                                for (let k of ['props', 'col']) {
                                                                                    if (component.hasOwnProperty(k) && Surface.isEmpty(component[k])) {
                                                                                        delete component[k]
                                                                                    }
                                                                                }
                                                                                if (component.hasOwnProperty('item') && null !== component.item && Surface.isEmpty(component.item)) {
                                                                                    delete component.item
                                                                                }
                                                                                if (componentMap.hasOwnProperty(el)) {
                                                                                    delete component.el
                                                                                    if (!formNamespaceStr.hasOwnProperty(el)) {
                                                                                        formNamespaceStr[el] = "use " + componentMap[el] + ";"
                                                                                    }
                                                                                    const className = componentMap[el].split('\\').pop()
                                                                                    formColumnsStr.push(`(new ${className}(${json2PhpArr(component, null)}))`)
                                                                                } else {
                                                                                    formColumnsStr.push(`(new Component(${json2PhpArr(component, null)}))`)
                                                                                }
                                                                            })

                                                                            return {
                                                                                formNamespaceStr, formColumnsStr
                                                                            }
                                                                        }
                                                                    }

                                                                    switch (curOutputType.value) {
                                                                        case 'table':
                                                                            switch (curOutputLang.value)  {
                                                                                case 'php':
                                                                                    outputData = (function(){
                                                                                        const options = json2PhpArr(outputHandler.getTableOptions(), 3)
                                                                                        const classStr = outputHandler.getTableColumn()
                                                                                        return `<?php
use surface\\api\\Vmodel;
use surface\\Component;
use surface\\components\\Table;
use surface\\components\\TableColumn;

$table = (new Table())
->props(
    [
        'modelValue' => new Vmodel('TableApi'),
        'columns' => [
            ${classStr.join(',\n            ')}
        ],
        'options' => ${options}
    ]
);

echo $table->view();

`
                                                                                    }())
                                                                                    break;
                                                                                case 'vue1':
                                                                                    outputData = (function (){
                                                                                        let columns = JSON.stringify(Surface.cloneDeep(tableColumns.value), null, 4);
                                                                                        let options = JSON.stringify(Surface.cloneDeep(tableOptions.value), null, 4);
                                                                                        const script = 'script'
                                                                                        return `<template>
    <s-table v-model="tableApi" :options="options" :columns="columns"></s-table>
</template>

<${script} setup>

import {ref} from 'vue'

const tableApi = ref(null)

const options = ${options};
const columns = ${columns};

</${script}>

`
                                                                                    }())
                                                                                    break;
                                                                                case 'vue2':
                                                                                    outputData = (function (){
                                                                                        let columns = formatJson(Surface.cloneDeep(tableColumns.value), 4);
                                                                                        let options = formatJson(Surface.cloneDeep(tableOptions.value), 4);
                                                                                        return `
import {ref} from 'vue'

export default defineComponent({
    name: 's-arrays',
    inheritAttrs: false,
    setup(props){
        const tableApi = ref(null)
        
        return () => new Surface.Render({
            el: "table",
            props: {
                "modelValue": tableApi.value,
                "onUpdate:modelValue": api => tableApi.value = api,
                options: ${options},
                columns: ${columns},
            }
        }).render()
    }
})
`
                                                                                    }())
                                                                                    break;
                                                                            }
                                                                            break;
                                                                        case 'form':
                                                                            switch (curOutputLang.value) {
                                                                                case 'php':
                                                                                    outputData = (function (){
                                                                                        let options = json2PhpArr(Surface.cloneDeep(formOptions.value), 3)
                                                                                        const {formColumnsStr, formNamespaceStr} = outputHandler.getPhpFormColumns()

                                                                                        return `<?php
use surface\\api\\Vmodel;
use surface\\Component;
use surface\\components\\Form;
${Object.values(formNamespaceStr).join('\n')}

$form = (new Form())
->props(
    [
        'modelValue' => new Vmodel('formApi'),
        'data' => new Vmodel('formData', []),
        'columns' => [
            ${formColumnsStr.join(',\n            ')}
        ],
        'options' => ${options}
    ]
);

echo $form->view();

`
                                                                                    }())
                                                                                    break;
                                                                                case 'vue1':
                                                                                    outputData = (function (){
                                                                                        let columns = JSON.stringify(Surface.cloneDeep(formColumns.value), null, 4);
                                                                                        let options = JSON.stringify(Surface.cloneDeep(formOptions.value), null, 4);

                                                                                        const script = 'script'

                                                                                       return `<template>
<s-form v-model="formApi" v-model:data="formData" :options="options" :columns="columns"></s-form>
</template>

<${script} setup>

import {ref} from 'vue'

const formApi = ref(null)
const formData = ref({})

const options = ${options};
const columns = ${columns};

</${script}>

`
                                                                                    }())
                                                                                    break;
                                                                                case 'vue2':

                                                                                    outputData = (function (){

                                                                                        let columns = formatJson(Surface.cloneDeep(formColumns.value), 4);
                                                                                        let options = formatJson(Surface.cloneDeep(formOptions.value), 4);
                                                                                        return `
import {ref} from 'vue'

export default defineComponent({
    name: 's-arrays',
    inheritAttrs: false,
    setup(props){
        const formApi = ref(null)
        const formData = ref({})
        
        return () => new Surface.Render({
            el: "form",
            props: {
                "modelValue": formApi.value,
                "onUpdate:modelValue": api => formApi.value = api,
                
                "data": formData.value,
                "onUpdate:data": data => formData.value = api,
                
                options: ${options},
                columns: ${columns},
            }
        }).render()
    }
})
`
                                                                                    }())
                                                                                    break;
                                                                            }
                                                                            break;
                                                                        case 'curd':
                                                                            switch (curOutputLang.value) {
                                                                                case 'php':
                                                                                    outputData = (function () {
                                                                                        const formOptionsStr = json2PhpArr(Surface.cloneDeep(formOptions.value), 3)
                                                                                        const {formColumnsStr, formNamespaceStr} = outputHandler.getPhpFormColumns()

                                                                                        const tableOptionsStr = json2PhpArr(outputHandler.getTableOptions(), 3)
                                                                                        const tableColumnStr = outputHandler.getTableColumn()

                                                                                        return `<?php

use surface\\Component;
use surface\\components\\TableColumn;
${Object.values(formNamespaceStr).join('\n')}

class Curd
{

    use \\surface\\helper\\Curd
    
    protected function searchColumns(): array
    {
        return [
            $this->addBtn(),
            $this->reloadBtn(),
        ];
    }

    protected function tableOptions(): array
    {
        return ${tableOptionsStr};
    }

    protected function tableColumns(): array
    {
        return [
            ${tableColumnStr.join(',\n            ')}
        ];
    }


    protected function formOptions(): array
    {
        return ${formOptionsStr};
    }
    
    protected function formColumns(): array
    {
        return [
            ${formColumnsStr.join(',\n            ')}
        ];
    }

}
`
                                                                                    }())
                                                                                    break;
                                                                                case 'vue1':
                                                                                    outputData = ":TODO:";
                                                                                    break;
                                                                                case 'vue2':
                                                                                    outputData = ":TODO:";
                                                                                    break;
                                                                            }
                                                                            break;
                                                                    }

                                                                    return outputData;
                                                                }
                                                            }
                                                        ]
                                                    }
                                                ]
                                            }
                                        }
                                    },
                                    {
                                        el: 'el-button',
                                        props: {
                                            type: "primary",
                                            style: "margin: 10px 100px",
                                            onClick() {
                                                copyText(outputData)
                                            }
                                        },
                                        children: "复制代码"
                                    }
                                ]
                            },
                            ...(
                                curPageTab.value === 'form' ?
                                    [
                                        {
                                            el: "draggable",
                                            props: {
                                                chosenClass: "s-chosen",
                                                class: "field-draggable-box el-row",
                                                animation: 100,
                                                group: {name: "curd", pull: false, put: true},
                                                onEnd: e => {
                                                    if (e.oldIndex === curFieldIndex.value) {
                                                        curFieldIndex.value = e.newIndex
                                                    } else if (e.oldIndex < curFieldIndex.value && e.newIndex >= curFieldIndex.value) {
                                                        // 前面的元素被拖动到后面
                                                        curFieldIndex.value -= 1
                                                    } else if (e.oldIndex > curFieldIndex.value && e.newIndex <= curFieldIndex.value) {
                                                        // 后面的元素被拖动到前面
                                                        curFieldIndex.value += 1
                                                    }
                                                },
                                                list: formColumns.value
                                            },
                                            children: {
                                                el: "component",
                                                __invoke: ({element, index}) => {
                                                    if (element.hasOwnProperty('component') && element.hasOwnProperty('icon')) {
                                                        let ele = Surface.cloneDeep(element.component);
                                                        if (!Array.isArray(ele)) {
                                                            ele = [ele]
                                                        }
                                                        // 重命名
                                                        ele.forEach(e => {
                                                            if (e.hasOwnProperty("name") && e.name.toUpperCase() === '__RANDOM') {
                                                                e.name = 's' + getRandomChar()
                                                            }
                                                        })
                                                        // 批量添加元素
                                                        nextTick(() => {
                                                            formColumns.value.splice(index, 1, ...ele)
                                                            if (index <= curFieldIndex.value) {
                                                                curFieldIndex.value += 1
                                                            }
                                                        })
                                                        element = ele[0]
                                                    }

                                                    if (!element.hasOwnProperty('props')) {
                                                        element.props = {}
                                                    }
                                                    if (!element.hasOwnProperty('item')) {
                                                        element.item = {}
                                                    }
                                                    const elTemp = Surface.cloneDeep(element)
                                                    const isActive = curFieldIndex.value === index
                                                    const colSpan = formOptions.value.props.inline ? '' : ('el-col el-col-' + 24)

                                                    if (elTemp.item) {
                                                        elTemp.item.labelWidth = (formOptions.value.props.inline ? "inherit" : (formOptions.value.props.labelWidth + "px"))
                                                    }
                                                    elTemp.props.disabled = true

                                                    let setJsonDataIng = false

                                                    return new Surface.Render({
                                                        el: 'div',
                                                        props: {
                                                            class: colSpan + ' item field ' + (isActive ? 'active' : ''),
                                                            onClick: async () => {
                                                                if (setJsonDataIng) return
                                                                setJsonDataIng = true
                                                                try{
                                                                    if (curComponentTab.value !== 'component') {
                                                                        curComponentTab.value = 'component'
                                                                    }
                                                                    curFieldIndex.value = index
                                                                    await reloadJsonEditor()
                                                                }catch (e){}
                                                                setJsonDataIng = false
                                                            }
                                                        },
                                                        children: [
                                                            function (){
                                                                const children = []
                                                                if (isActive) {
                                                                    children.push(new Surface.Render({
                                                                        el: 'icon',
                                                                        props: {
                                                                            class: "close", icon: 'Close',
                                                                            onClick() {
                                                                                formColumns.value.splice(index, 1)
                                                                            }
                                                                        },
                                                                    }))
                                                                }
                                                                children.push(elTemp)
                                                                return children
                                                            }
                                                        ]
                                                    }).withFormCustom().render()
                                                },
                                                slot: "item"
                                            }
                                        }
                                    ] :
                                    [
                                        {
                                            el: "div",
                                            props: {
                                                class: "table-box",
                                            },
                                            children: {
                                                el: "table",
                                                props: {
                                                    key: uniqueKeyMap.table || "",
                                                    options: Surface.cloneDeep(tableOptions.value),
                                                    columns: [
                                                        ...tableColumns.value.map(field => {
                                                            const index = tableColumns.value.indexOf(field)
                                                            return {
                                                                el: "table-column",
                                                                props: {
                                                                    ...field.props,
                                                                    key: uniqueKeyMap.tableColumns || "",
                                                                },
                                                                children: (function (){
                                                                    const childTemp = field.hasOwnProperty('children')
                                                                        ? (Array.isArray(field.children) ? field.children : [field.children])
                                                                        : []

                                                                    const children = [
                                                                        {
                                                                            el: "draggable",
                                                                            slot: 'header',
                                                                            props: {
                                                                                sort: false,
                                                                                ghostClass: "s-ghost",
                                                                                class: "table-column",
                                                                                'data-index': index,
                                                                                chosenClass: "s-chosen",
                                                                                animation: 100,
                                                                                group: {
                                                                                    name: "table-curd",
                                                                                    pull: "clone",
                                                                                    put: true
                                                                                },
                                                                                list: [field],
                                                                                onEnd: e => {
                                                                                    let oldIndex = parseInt(e.from.getAttribute("data-index"));
                                                                                    let newIndex = parseInt(e.to.getAttribute("data-index"));

                                                                                    const newFields = Surface.cloneDeep(tableColumns.value)
                                                                                    const moveField = newFields[oldIndex]

                                                                                    if (oldIndex < newIndex) {
                                                                                        // 前面的元素被拖动到后面
                                                                                        let diffNum = newIndex - oldIndex
                                                                                        let tempFields = [...newFields.splice(oldIndex + 1, diffNum), moveField]
                                                                                        tableColumns.value.splice(oldIndex, diffNum + 1, ...tempFields)
                                                                                    } else if (oldIndex > newIndex) {
                                                                                        // 后面的元素被拖动到前面
                                                                                        let diffNum = oldIndex - newIndex
                                                                                        let tempFields = [moveField, ...newFields.splice(newIndex, diffNum)]
                                                                                        tableColumns.value.splice(newIndex, diffNum + 1, ...tempFields)
                                                                                    }
                                                                                }
                                                                            },
                                                                            children: {
                                                                                el: "component",
                                                                                __invoke: ({element}) => {
                                                                                    let setJsonDataIng = false
                                                                                    const isActive = curColumnIndex.value === index
                                                                                    return new Surface.Render({
                                                                                        el: 'div',
                                                                                        props: {
                                                                                            class: "item field " + (isActive ? 'active' : ''),
                                                                                            onClick: async () => {
                                                                                                if (setJsonDataIng) return
                                                                                                setJsonDataIng = true
                                                                                                try{
                                                                                                    if (curComponentTab.value !== 'component') {
                                                                                                        curComponentTab.value = 'component'
                                                                                                    }
                                                                                                    curColumnIndex.value = index
                                                                                                    await reloadJsonEditor()
                                                                                                }catch (e){}
                                                                                                setJsonDataIng = false
                                                                                            }
                                                                                        },
                                                                                        children: [
                                                                                            function (){
                                                                                                const children = []
                                                                                                if (isActive) {
                                                                                                    children.push({
                                                                                                        el: 'icon',
                                                                                                        props: {
                                                                                                            class: "close",icon: 'Close',
                                                                                                            onClick() {
                                                                                                                tableColumns.value.splice(index, 1)
                                                                                                            }
                                                                                                        },
                                                                                                    })
                                                                                                }

                                                                                                let headerTemp = field.props?.label || field.props?.prop || '-'
                                                                                                for (let c of childTemp) {
                                                                                                    if (c?.slot === 'header') {
                                                                                                        headerTemp = Surface.cloneDeep(c)
                                                                                                        // header组件只显示一个
                                                                                                        break;
                                                                                                    }
                                                                                                }
                                                                                                children.push(headerTemp)
                                                                                                return children
                                                                                            }
                                                                                        ]
                                                                                    }).render()
                                                                                },
                                                                                slot: "item"
                                                                            }
                                                                        }
                                                                    ]

                                                                    for (let c of childTemp) {
                                                                        if (c?.slot !== 'header') {
                                                                            children.push(Surface.cloneDeep(c))
                                                                        }
                                                                    }

                                                                    return children
                                                                })()

                                                            }
                                                        })
                                                    ],
                                                    autoload: !!tableOptions.value.request.url
                                                },
                                                children: {
                                                    el: "button",
                                                    slot: 'header',
                                                    props: {
                                                        type: 'primary',
                                                        onClick: async () => {
                                                            let name = "name-" + getRandomChar(3)
                                                            tableColumns.value.push({
                                                                props: {
                                                                    prop: name,
                                                                    label: name,
                                                                }
                                                            })

                                                            try{
                                                                if (curColumnIndex.value === null && curComponentTab.value !== 'options') {
                                                                    curComponentTab.value = 'options'
                                                                }
                                                                // 生成数据
                                                                if (!tableOptions.value.request.url) {
                                                                    reloadTableData()
                                                                }
                                                                await reloadJsonEditor()
                                                            } catch (e){}

                                                        },
                                                    },
                                                    children: "新增一列"
                                                }
                                            }
                                        }
                                    ]
                            )
                        ]
                    },
                    {
                        el: "div",
                        props: {class: "right"},
                        children: [
                            {
                                el: "el-tabs",
                                props: {
                                    modelValue: curComponentTab.value,
                                    'onUpdate:modelValue': async val => {
                                        let oldVal = curComponentTab.value
                                        curComponentTab.value = val
                                        try{
                                            await reloadJsonEditor()
                                        }catch (e){
                                            curComponentTab.value = oldVal
                                        }
                                    }
                                },
                                children: [
                                    {
                                        el: "el-tab-pane",
                                        props: {name: "component"},
                                        children: [
                                            {
                                                el: "div",
                                                slot: 'label',
                                                props: {
                                                    class: "tab-label"
                                                },
                                                children: [
                                                    "组件配置",
                                                    {
                                                        el: 'el-popover',
                                                        props: {
                                                            trigger: 'click',
                                                            width: 300
                                                        },
                                                        children: [
                                                            {
                                                                el: 'div',
                                                                props: {
                                                                    innerHTML: `
                                                                    <div><a href="https://doc.zsw.ink/#/surface/component?id=%e7%bb%84%e4%bb%b6%e6%9e%84%e6%88%90" target="_blank">参考配置</a><div>
                                                                    <div><b>el</b>：组件名称(任何实现v-model的组件)<div>
                                                                    <div><b>props</b>：组件事件、属性、样式等<div>
                                                                    <div><b>children</b>：子组件<div>
                                                                    ` + (curPageTab.value === 'form' ?
                                                                        `
                                                                    <br><div><a href="https://doc.zsw.ink/#/surface/common/form-column" target="_blank">表单组件特有属性</a><div>
                                                                    <div><b>label</b>：名称（item为null时无效）<div>
                                                                    <div><b>name </b>：字段名（为空时不会双向绑定）<div>
                                                                    <div><b>value</b>：默认值<div>
                                                                    <div><b>col  </b>：布局col(覆盖form的col)<div>
                                                                    <div><b>item </b>：form-item组件 null时移除item<div>` :
                                                                        `
                                                                    <br><div><a href="https://doc.zsw.ink/#/php-surface/table/table-column" target="_blank">表格列配置</a><div>
                                                                    <div>表格一级列只能是<a href="https://element-plus.gitee.io/zh-CN/component/table.html#table-column-%E5%B1%9E%E6%80%A7" target="_blank">table-column组件</a><div>
                                                                        `)
                                                                }
                                                            },
                                                            {
                                                                el: 'icon',
                                                                slot: 'reference',
                                                                props: {
                                                                    icon: 'WarningFilled'
                                                                }
                                                            },
                                                        ]
                                                    }
                                                ]
                                            }
                                        ]
                                    },
                                    {
                                        el: "el-tab-pane",
                                        props: {name: "options"},
                                        children: [
                                            {
                                                el: "div",
                                                slot: 'label',
                                                props: {
                                                    class: "tab-label"
                                                },
                                                children: [
                                                    function (){
                                                        return curPageTab.value === 'form' ? "表单配置" : "表格配置"
                                                    },
                                                    {
                                                        el: 'el-popover',
                                                        props: {
                                                            trigger: 'click',
                                                            width: 200
                                                        },
                                                        children: [
                                                            {
                                                                el: 'div',
                                                                props: {
                                                                    innerHTML: curPageTab.value === 'form' ? `
                                                                    <div><a href="https://doc.zsw.ink/#/surface/common/form?id=options%e5%8f%82%e6%95%b0" target="_blank">表单options配置</a><div>
                                                                    <div><a href="https://element-plus.gitee.io/zh-CN/component/form.html#table-%E5%B1%9E%E6%80%A7" target="_blank">options.props配置</a><div>
                                                                    ` : `
                                                                    <div><a href="https://doc.zsw.ink/#/surface/common/table" target="_blank">表格options配置</a><div>
                                                                    <div><a href="https://element-plus.gitee.io/zh-CN/component/table.html#table-%E5%B1%9E%E6%80%A7" target="_blank">options.props配置</a><div>
                                                                    `
                                                                }
                                                            },
                                                            {
                                                                el: 'icon',
                                                                slot: 'reference',
                                                                props: {
                                                                    icon: 'WarningFilled'
                                                                }
                                                            },
                                                        ]
                                                    }
                                                ]
                                            }
                                        ]
                                    },
                                ]
                            },
                            {el: "div", props: {class: "json-editor"}}
                        ]
                    }]
            }).render()
    }
})
